package com.retail.lottery.colalottery.config;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.nimbusds.jose.shaded.gson.Gson;
import com.retail.lottery.colalottery.enums.CommonEnum;
import com.retail.lottery.colalottery.utils.AesUtil;
import com.retail.lottery.colalottery.utils.DateUtil;
import com.retail.lottery.colalottery.utils.RequestParamUtils;
import com.retail.lottery.colalottery.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//@Component
@Slf4j
public class SignFilter implements Filter {

    @Value("${aes-key}")
    public String aesKsy;
    @Value("${aes-iv}")
    public String aesIv;

    private static final Long timeGap = 5 * 60 * 1000L;

    private static final Gson gson = new Gson();
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException  {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String version = httpRequest.getHeader("Version");
        if("V2".equals(version)){
            String sign = ((HttpServletRequest) request).getHeader("Signature");
            Map<String, Object> allParams = RequestParamUtils.getAllParams(httpRequest);
            if (!verifySign(allParams, sign)){
                //返回指定响应体
                httpResponse.setContentType("application/json");
                httpResponse.setStatus(500);
                ResultVO<?> signError = new ResultVO().error(CommonEnum.SIGN_FAIL);
                httpResponse.getWriter().write(JSONObject.toJSONString(signError));
                return;
            }
        }
        chain.doFilter(request, response);
    }

    private boolean verifySign(Map<String, Object> allParams, String sign) {
        Object timestamp = allParams.get("timestamp");
        if(Objects.isNull(timestamp)){
            log.error("验签参数错误,时间戳为空");
            return false;
        }
        LocalDateTime time = Instant.ofEpochMilli(Long.valueOf(String.valueOf(timestamp)))
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        if(DateUtil.timeGap(time, LocalDateTime.now(), timeGap)){
            log.error("验签参数错误,时间戳错误");
            return false;
        }
        String concatParams = concatParams(allParams);
        //log.info("concatParams:{}", concatParams);
        String signClient = AesUtil.encryptBase64(concatParams, aesKsy, aesIv);
        //log.info("signClient:{}", signClient);
        boolean signResult = signClient.equals(sign);
        log.info("验签结果:{}", signResult);
        return signResult;

    }

    private static String concatParams(Map<String, Object> paramMap) {
        Object[] key_arr = paramMap.keySet().toArray();
        Arrays.sort(key_arr);
        String str = "";
        for(Object key : key_arr) {
            String val = "";
            Object obj = paramMap.get(key);
            if(obj == null){
                continue;
            }
            if (obj instanceof Number
                    || obj instanceof Boolean
                    || obj instanceof Character
                    || obj instanceof String) {
                val = String.valueOf(obj);
            }else{
                // 对象转 JSON
                try {
                    val = gson.toJson(obj);
                } catch (Exception e) {
                    val = obj.toString();
                }
            }
            if(StringUtils.isBlank(val)){
                continue;
            }
            str = str + "&" + key + "=" + val;
        }
        return str.replaceFirst("&", "");
    }

}
